
#include <stdio.h>
#include <BKeyEvent>
#include <BCharEvent>
#include <BMouseEvent>
#include <BDragEvent>
#include <BDrag>

#include "IGlobal.h"
#include "member_BWidget.h"
#include "member_BObject.h"
#include "member_BLayout.h"
#include "member_BStyle.h"
#include "member_BEvent.h"

using namespace BWE;

member_BWidget::member_BWidget(BWidget* widget)
{
	boss = widget;
	window = 0;
	pixmap = 0;

	frameless = false;
	visible = true;
	refresh = true;
	dirty = true;
	dirtyStyle = false;
	fbo_resized = true;
	fbo = 0;
	rbo_depth = 0;
	tbo = 0;
	transparency = 255;
	layered = false;

	modal = false;
	focusable = true;
	focused = false;
	floating = true;
	droppable = false;
	parent = 0;
	border = 1;
	perch = 0;
	margin = 1;
	sizePolicy = Policy_Preferred | Policy_Dynamic;
	size.set(100, 100);
	minSize.set(0, 0);
	maxSize.set(999999, 999999);

	upperLayout = 0;
	freshRects();
}
member_BWidget::~member_BWidget()
{
	if (tbo)
		glDeleteTextures(1, &tbo);
	if (rbo_depth)
		glDeleteRenderbuffers(1, &rbo_depth);
	if (fbo)
		glDeleteFramebuffers(1, &fbo);
}

bool member_BWidget::ignored() const
{
	if (upperLayout)
	{
		const BRect& rect = upperLayout->area(boss);
		if (rect.empty())
			return false;
		BLayout* layout = upperLayout;
		while (layout)
		{
			if (!layout_member(layout)->visible)
				return false;
			layout = layout_member(layout)->parent;
		}
	}
	return true;
}
void member_BWidget::freshEnabled(bool enabled)
{
	state.enabled = enabled;
	if (state.enabled)
	{
		state.enabled = object_member(boss)->enabled;
	}
	if (state.enabled)
	{
		BLayout* layout = upperLayout;
		while (layout)
		{
			if (!object_member(layout)->enabled)
			{
				state.enabled = false;
				break;
			}
			layout = layout_member(layout)->parent;
		}
	}
	for (int i = 0; i < children.size(); i++)
	{
		BWidget* child = children[i];
		widget_member(child)->freshEnabled(state.enabled);
	}
	refresh = true;
}

void member_BWidget::frame()
{
	int width = size.width();
	int height = size.height();

	if (fbo == 0 || rbo_depth == 0 || tbo == 0)
		fbo_resized = true;
	if (fbo_resized)
	{
		GLint backup_frame_buffer;
		glGetIntegerv(GL_FRAMEBUFFER_BINDING, &backup_frame_buffer);
		if (!fbo)
		{
			glGenFramebuffers(1, &fbo);
			glGenRenderbuffers(1, &rbo_depth);
		}
		if (fbo)
		{
			glBindFramebuffer(GL_FRAMEBUFFER, fbo);
			glBindRenderbuffer(GL_RENDERBUFFER, rbo_depth);
			glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT, width, height);
			glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, rbo_depth);
		}
		if (!tbo)
		{
			glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
			glGenTextures(1, &tbo);
		}
		if (tbo)
		{
			glBindTexture(GL_TEXTURE_2D, tbo);
			glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
			glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
			glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
			glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
			glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_BGRA, GL_UNSIGNED_BYTE, 0);
			glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, tbo, 0);
		}
		fbo_resized = false;
		glBindFramebuffer(GL_FRAMEBUFFER, backup_frame_buffer);
	}
	if (fbo)
	{
		GLint backup_frame_buffer;
		glGetIntegerv(GL_FRAMEBUFFER_BINDING, &backup_frame_buffer);

		glBindFramebuffer(GL_FRAMEBUFFER, fbo);
		glDrawBuffer(GL_COLOR_ATTACHMENT0);
		glReadBuffer(GL_COLOR_ATTACHMENT0);

		glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
		glClear(GL_COLOR_BUFFER_BIT);
		glDisable(GL_LIGHTING);
		glDisable(GL_DEPTH_TEST);
		glDisable(GL_CULL_FACE);

		glViewport(0, 0, size.width(), size.height());

		glMatrixMode(GL_PROJECTION);
		glLoadIdentity();
		glOrtho(0, size.width(), size.height(), 0, -1, 1);

		glMatrixMode(GL_MODELVIEW);
		glLoadIdentity();

		glEnable(GL_BLEND);
		glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE);
		glBlendEquationSeparate(GL_FUNC_ADD, GL_FUNC_ADD);

		state.font = boss->font();
		state.style = boss->realStyle();

		paintEvent.reset(Event_Paint);
		this->procEvent(paintEvent);
		dirty = false;
		if (layered)
		{
			glEnable(GL_TEXTURE_2D);
			for (int i = 0; i < children.size(); i++)
			{
				BWidget* child = children[i];
				if (!widget_member(child)->visible)
					continue;
				if (!widget_member(child)->ignored())
					continue;
				if (widget_member(child)->floating)
					drawWidget(child, size, child->pos(), size.height());
				else
					drawWidget(child, rectCenter, child->pos(), size.height());
			}
			glBindTexture(GL_TEXTURE_2D, 0);
			glDisable(GL_TEXTURE_2D);
		}
		boss->emit(Signal_Frame);

		glBindFramebuffer(GL_FRAMEBUFFER, backup_frame_buffer);
	}
}
void member_BWidget::drawWidget(BWidget* widget, const BRect& clip, const BPoint& offset, int frameHeight)
{
	if (!widget_member(widget)->visible)
		return;
	BSize size = widget->size();
	BRect ab_rect(offset, size);
	BRect view = ab_rect & clip;
	if (view.empty())
		return;

	glViewport(view.x(), frameHeight - view.bottom(), view.width(), view.height());

	BRect area(view.pos() - ab_rect.pos(), view.size());
	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();
	glOrtho(area.left() + 1, area.right(), area.bottom() - 1, area.top(), -1, 1);

	if (widget_member(widget)->tbo)
	{
		int width = widget_member(widget)->size.width();
		int height = widget_member(widget)->size.height();
		glColor4ub(255, 255, 255, widget_member(widget)->transparency);
		glBindTexture(GL_TEXTURE_2D, widget_member(widget)->tbo);
		glBegin(GL_QUADS);
		glTexCoord2f(0.0f, 1.0f);		glVertex2i(0, 0);
		glTexCoord2f(0.0f, 0.0f);		glVertex2i(0, height);
		glTexCoord2f(1.0f, 0.0f);		glVertex2i(width, height);
		glTexCoord2f(1.0f, 1.0f);		glVertex2i(width, 0);
		glEnd();
	}
	if (!widget_member(widget)->layered)
	{
		BRect ab_crect = rectCenter + offset;
		BRect cview = ab_crect & clip;
		BWidgetHolderArray& children = widget_member(widget)->children;
		for (int i = 0; i < children.size(); i++)
		{
			BWidget* child = children[i];
			if (!widget_member(child)->visible)
				continue;
			if (!widget_member(child)->ignored())
				continue;
			if (widget_member(child)->floating)
				drawWidget(child, view, offset + child->pos(), frameHeight);
			else
				drawWidget(child, cview, offset + child->pos(), frameHeight);
		}
	}
}

void member_BWidget::syncWindowPos(const BPoint& wpos)
{
	if (pos != wpos)
	{
		pos = wpos;
		//BEvent moveEvent(Event_Move);
		//procEvent(moveEvent);
	}
}
void member_BWidget::syncWindowSize(const BSize& wsize)
{
	BSize temp = wsize;
	temp.limit(minSize, maxSize);
	if (size != temp)
	{
		size = temp;
		fbo_resized = true;
		resized = true;
		freshRects();
		boss->adjust();
		BEvent resizeEvent(Event_Resize);
		procEvent(resizeEvent);
	}
}

bool member_BWidget::procEvent(const BEvent& event)
{
	if (event_member(&event)->window == 0)
	{
		BWidget* root = boss->root();
		event_member(&event)->window = widget_member(root)->window;
	}
	Event type = event.type();
	if (type == Event_Move)
	{
		dirtyPixmaps();
	}
	else if (type == Event_Resize)
	{
		boss->fresh();
		dirtyPixmaps();
	}
	else if (type == Event_Adjust)
	{
		boss->fresh();
	}
	else if (type == Event_Active)
	{
		boss->fresh();
	}
	else if (type == Event_Style)
	{
		if (realStyle)
		{
			applyStyle();
			applyRoundStyle();
		}
		if (resized)
		{
			freshRects();
			BEvent resizeEvent(Event_Resize);
			resizeEvent.setValue(size);
			procEvent(resizeEvent);
		}
		boss->fresh();
		dirtyPixmaps();
		dirtyUpperLayout();
	}
	else if (type == Event_Show)
	{
		freshLayoutPerch();
		if (resized)
		{
			freshRects();
			BEvent resizeEvent(Event_Resize);
			resizeEvent.setValue(size);
			procEvent(resizeEvent);
		}
		adjustDirtyLayouts();
		dirtyPixmaps();
	}
	if (type == Event_Hide)
	{
		dirtyPixmaps();
	}
	if (type == Event_Fresh)
	{
		if (dirtyStyle)
		{
			BEvent styleEvent(Event_Style);
			dispenseStyles(styleEvent);
			dirtyStyle = false;
		}
		freshLayoutPerch();
		if (resized)
		{
			freshRects();
			BEvent resizeEvent(Event_Resize);
			resizeEvent.setValue(size);
			procEvent(resizeEvent);
		}
		adjustDirtyLayouts();
		if (!state.shown)
		{
			state.shown = true;

			BEvent activeEvent(Event_Active);
			activeEvent.setValue(state.actived);
			procEvent(activeEvent);

			BEvent showEvent(Event_Show);
			procEvent(showEvent);
		}
	}
	bool accepted = false;
	if (type == Event_Paint)
	{
		accepted = boss->event(event);
		for (int i = 0; i < layouts.size(); i++)
		{
			BLayout* layout = layouts[i];
			if (layout->visible() && layout_member(layout)->event(event))
			{
				accepted = true;
			}
		}
	}
	else
	{
		if (type >= Event_Active && type <= Event_MouseRelease)
		{
			for (int i = 0; i < layouts.size(); i++)
			{
				BLayout* layout = layouts[i];
				if (layout->enabled() && layout_member(layout)->event(event))
				{
					accepted = true;
					break;
				}
			}
			if (!accepted && state.enabled)
				accepted = boss->event(event);
		}
		else
		{
			if (!accepted)
				accepted = boss->event(event);
		}
	}
	return accepted;
}

void DispenseLevelStyles(BWidget* widget, BWidget* upper)
{
	if (BWidget* parent = widget_member(upper)->parent)
	{
		DispenseLevelStyles(widget, parent);
	}
	if (BStyle* style = widget_member(upper)->realStyle)
	{
		style_member(style)->apply(widget);
	}
}
void member_BWidget::dispenseStyles(BEvent& event)
{
	if (realStyle)
	{
		realStyle->clearSubs();
		realStyle->clearTrans();
		realStyle->clearColors();
		realStyle->clearImages();
		realStyle->clearIcons();
		realStyle->clearChildren();
	}
	style_member(app_style)->apply(boss);
	if (parent)
	{
		DispenseLevelStyles(boss, parent);
	}
	if (style)
	{
		if (realStyle.empty())
			realStyle = new BStyle();
		style_member(realStyle)->overlap(style);
		style_member(style)->apply(boss);
	}
	for (int i = 0; i < children.size(); i++)
	{
		BWidget* child = children[i];
		widget_member(child)->dispenseStyles(event);
		widget_member(child)->dirtyStyle = false;
	}
	event.setValue(boss->realStyle());
	this->procEvent(event);
	if (realStyle)
	{
		for (int i = 0; i < layouts.size(); i++)
		{
			BLayout* layout = layouts[i];
			BStyle* style = realStyle->sub(layout->name());
			if (!style && layout_member(layout)->part == Part_Center)
				style = realStyle->sub("center");
			if (!style && layout_member(layout)->part == Part_Title)
				style = realStyle->sub("title");
			if (!style && layout_member(layout)->part == Part_Left)
				style = realStyle->sub("left");
			if (!style && layout_member(layout)->part == Part_Top)
				style = realStyle->sub("top");
			if (!style && layout_member(layout)->part == Part_Right)
				style = realStyle->sub("right");
			if (!style && layout_member(layout)->part == Part_Bottom)
				style = realStyle->sub("bottom");
			if (!style && layout_member(layout)->part == Part_LeftTop)
			{
				style = realStyle->sub("left-top");
				if (!style)
					style = realStyle->sub("top-left");
			}
			if (!style && layout_member(layout)->part == Part_RightTop)
			{
				style = realStyle->sub("right-top");
				if (!style)
					style = realStyle->sub("top-right");
			}
			if (!style && layout_member(layout)->part == Part_LeftBottom)
			{
				style = realStyle->sub("left-bottom");
				if (!style)
					style = realStyle->sub("bottom-left");
			}
			if (!style && layout_member(layout)->part == Part_RightBottom)
			{
				style = realStyle->sub("right-bottom");
				if (!style)
					style = realStyle->sub("bottom-right");
			}
			event.setValue(style);
			if (style && layout_member(layout)->event(event))
			{
				resized = true;
			}
		}
	}
}
void member_BWidget::applyStyle()
{
	const BValue& widthValue = realStyle->value(Value_Width);
	if (widthValue.valid())
	{
		fixedSize.width() = widthValue;
		sizePolicy.widthPolicy() = Policy_Fixed;
		resized = true;
	}
	const BValue& heightValue = realStyle->value(Value_Height);
	if (heightValue.valid())
	{
		fixedSize.height() = heightValue;
		sizePolicy.heightPolicy() = Policy_Fixed;
		resized = true;
	}
	const BValue& baseSizeValue = realStyle->value(Value_Base_Size);
	if (baseSizeValue.valid())
	{
		size = baseSizeValue;
		resized = true;
	}
	const BValue& borderValue = realStyle->value(Value_Border);
	if (borderValue.valid())
	{
		border = borderValue;
		resized = true;
	}
	const BValue& perchLeftValue = realStyle->value(Value_Perch_Left);
	if (perchLeftValue.valid())
	{
		perch.left() = perchLeftValue;
		resized = true;
	}
	const BValue& perchRightValue = realStyle->value(Value_Perch_Right);
	if (perchRightValue.valid())
	{
		perch.right() = perchRightValue;
		resized = true;
	}
	const BValue& perchTopValue = realStyle->value(Value_Perch_Top);
	if (perchTopValue.valid())
	{
		perch.top() = perchTopValue;
		resized = true;
	}
	const BValue& perchBottomValue = realStyle->value(Value_Perch_Bottom);
	if (perchBottomValue.valid())
	{
		perch.bottom() = perchBottomValue;
		resized = true;
	}
	const BValue& marginLeftValue = realStyle->value(Value_Margin_Left);
	if (marginLeftValue.valid())
	{
		margin.left() = marginLeftValue;
		resized = true;
	}
	const BValue& marginTopValue = realStyle->value(Value_Margin_Top);
	if (marginTopValue.valid())
	{
		margin.top() = marginTopValue;
		resized = true;
	}
	const BValue& marginRightValue = realStyle->value(Value_Margin_Right);
	if (marginRightValue.valid())
	{
		margin.right() = marginRightValue;
		resized = true;
	}
	const BValue& marginBottomValue = realStyle->value(Value_Margin_Bottom);
	if (marginBottomValue.valid())
	{
		margin.bottom() = marginBottomValue;
		resized = true;
	}
	const BValue& titleValue = realStyle->value(Value_Title);
	if (titleValue.valid())
	{
		this->title = (const BString&)titleValue;
		boss->emit(Signal_TitleChanged, titleValue);
		if (window)
		{
			window->setWindowTitle(title);
		}
	}
	BIcon* titleIcon = realStyle->icon(Icon_Title);
	if (titleIcon)
	{
		this->titleIcon = titleIcon;
		boss->emit(Signal_TitleIconChanged, titleIcon);
		if (window)
		{
			window->setWindowIcon(titleIcon);
		}
	}
}
void member_BWidget::applyRoundStyle()
{
	BSize radiusLeftTop;
	BSize radiusRightTop;
	BSize radiusLeftBottom;
	BSize radiusRightBottom;
	if (round)
	{
		radiusLeftTop = round->radiusLeftTop;
		radiusRightTop = round->radiusRightTop;
		radiusLeftBottom = round->radiusLeftBottom;
		radiusRightBottom = round->radiusRightBottom;
	}

	const BValue& topLeftRadiusValue = realStyle->value(Value_Radius_Left_Top);
	if (topLeftRadiusValue.valid())
		radiusLeftTop = topLeftRadiusValue;

	const BValue& topRightRadiusValue = realStyle->value(Value_Radius_Right_Top);
	if (topRightRadiusValue.valid())
		radiusRightTop = topRightRadiusValue;

	const BValue& bottomLeftRadiusValue = realStyle->value(Value_Radius_Left_Bottom);
	if (bottomLeftRadiusValue.valid())
		radiusLeftBottom = bottomLeftRadiusValue;

	const BValue& bottomRightRadiusValue = realStyle->value(Value_Radius_Right_Bottom);
	if (bottomRightRadiusValue.valid())
		radiusRightBottom = bottomRightRadiusValue;

	if (radiusLeftTop.empty() && radiusRightTop.empty() && radiusLeftBottom.empty() && radiusRightBottom.empty())
	{
		if (round)
		{
			round = 0;
			resized = true;
		}
	}
	else
	{
		if (round.empty())
			round = new IRound();
		round->radiusLeftTop = radiusLeftTop;
		round->radiusRightTop = radiusRightTop;
		round->radiusLeftBottom = radiusLeftBottom;
		round->radiusRightBottom = radiusRightBottom;
		resized = true;
	}
}

void member_BWidget::dirtyPixmaps()
{
	if(pixmap)
		pixmap->dirty();
	BWidget* widget = parent;
	while (widget)
	{
		if (BPixmap* pixmap = widget_member(widget)->pixmap)
			pixmap->dirty();
		widget = widget_member(widget)->parent;
	}
}
void member_BWidget::freshRects()
{
	int b = border;
	int w = size.width();
	int h = size.height();

	int pleft = perch.left();
	int pright = perch.right();
	int ptop = perch.top();
	int pbottom = perch.bottom();

	int mleft = margin.left();
	int mright = margin.right();
	int mtop = margin.top();
	int mbottom = margin.bottom();

	int cx = b + pleft + mleft;
	int cy = b + ptop + mtop;
	int cw = w - b - pleft - mleft - mright - pright - b;
	int ch = h - b - ptop - mtop - mbottom - pbottom - b;

	rectTitle.set(b, b, w - b - b, ptop);
	rectTop.set(b + pleft, b, w - b - pleft - b - pright, ptop);
	rectRight.set(w - b - pright, b + ptop, pright, h - b - b - ptop - pbottom);
	rectLeft.set(b, b + ptop, pleft, h - b - b - ptop - pbottom);
	rectBottom.set(b + pleft, h - b - pbottom, w - b - b - pleft - pright, pbottom);
	rectCenter.set(cx, cy, cw, ch);

	resized = false;

	if (round)
	{
		round->widgetSize = size;
		round->centerLeftTop.set(round->radiusLeftTop.width(), round->radiusLeftTop.height());
		round->centerRightTop.set(size.width() - round->radiusRightTop.width(), round->radiusRightTop.height());
		round->centerLeftBottom.set(round->radiusLeftBottom.width(), size.height() - round->radiusLeftBottom.height());
		round->centerRightBottom.set(size.width() - round->radiusRightBottom.width(), size.height() - round->radiusRightBottom.height());
		freshRoundPoints();
	}
}
void member_BWidget::freshRoundPoints()
{
	BPointfArray outerPoints;
	BPointfArray innerPoints;

	BRectf outerRect(0, 0, size.width(), size.height());
	BRectf innerRect(border, border, size.width() - border - border, size.height() - border - border);
	round->createPoints(outerRect, outerPoints);
	outerPoints.append(outerPoints.first());
	round->createPoints(innerRect, innerPoints);
	innerPoints.append(innerPoints.first());
	round->createTriangles(outerPoints, innerPoints, round->borderPoints);

	round->backgroundPoints = innerPoints;
	round->backgroundPoints.prepend(rectCenter.center());

	innerRect.left() = (float)rectLeft.right();
	innerRect.top() = (float)rectTop.bottom();
	innerRect.right() = (float)rectRight.left();
	innerRect.bottom() = (float)rectBottom.top();

	outerPoints = innerPoints;
	if (innerRect.valid())
	{
		round->createPoints(innerRect, innerPoints);
		innerPoints.append(innerPoints.first());
	}
	else
	{
		innerPoints.reset();
		innerPoints << innerRect.center();
	}
	round->createTriangles(outerPoints, innerPoints, round->perchPoints);

	outerPoints = innerPoints;
	round->createPoints(rectCenter, innerPoints);
	innerPoints.append(innerPoints.first());
	round->createTriangles(outerPoints, innerPoints, round->marginPoints);

	round->centerPoints = innerPoints;
	round->centerPoints.prepend(rectCenter.center());
}
void member_BWidget::freshLayoutPerch()
{
	BPerch tempPerch = perch;
	for (int i = 0; i < layouts.size(); i++)
	{
		BLayout* layout = layouts[i];
		if (layout->enabled() && layout_member(layout)->dirty)
		{
			BSize hsize = layout->preferSize();
			if (layout_member(layout)->part == Part_Title && perch.top() < hsize.height())
				tempPerch.top() = hsize.height();
			if (layout_member(layout)->part == Part_Top && perch.top() < hsize.height())
				tempPerch.top() = hsize.height();
			if (layout_member(layout)->part == Part_Left && perch.left() < hsize.width())
				tempPerch.left() = hsize.width();
			if (layout_member(layout)->part == Part_Right && perch.right() < hsize.width())
				tempPerch.right() = hsize.width();
			if (layout_member(layout)->part == Part_Bottom && perch.bottom() < hsize.height())
				tempPerch.bottom() = hsize.height();
		}
	}
	if (tempPerch != perch)
	{
		perch = tempPerch;
		resized = true;
	}
}
void member_BWidget::adjustDirtyLayouts()
{
	bool adjusted = false;
	for (int i = 0; i < layouts.size(); i++)
	{
		BLayout* layout = layouts[i];
		if (layout_member(layout)->visible && layout_member(layout)->dirty)
		{
			if (layout_member(layout)->part == Part_Center)
				layout->setRect(rectCenter);
			else if (layout_member(layout)->part == Part_Title)
				layout->setRect(rectTitle);
			else if (layout_member(layout)->part == Part_Top)
				layout->setRect(rectTop);
			else if (layout_member(layout)->part == Part_Left)
				layout->setRect(rectLeft);
			else if (layout_member(layout)->part == Part_Right)
				layout->setRect(rectRight);
			else if (layout_member(layout)->part == Part_Bottom)
				layout->setRect(rectBottom);
			layout->adjust();
			layout_member(layout)->dirty = false;
			adjusted = true;
		}
	}
	if (adjusted)
	{
		BEvent adjustEvent(Event_Adjust);
		this->procEvent(adjustEvent);
	}
}

void member_BWidget::dirtyLayout()
{
	for (int i = 0; i < layouts.size(); i++)
	{
		BLayout* layout = layouts[i];
		if (layout_member(layout)->part)
		{
			layout_member(layout)->dirty = true;
		}
	}
}
void member_BWidget::dirtyUpperLayout()
{
	if (upperLayout)
	{
		upperLayout->dirty(boss);
		if (parent)
		{
			widget_member(parent)->dirtyUpperLayout();
		}
	}
}
